package server

import (
	"context"
	"time"

	"github.com/devops-smartbot/devops-smartbot/services/integration-service/internal/models"
	"github.com/devops-smartbot/devops-smartbot/services/integration-service/internal/service"
	integrationv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/integration/v1"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/timestamppb"
)

type IntegrationGRPCServer struct {
	integrationv1.UnimplementedIntegrationServiceServer
	service *service.IntegrationService
	logger  *zap.Logger
}

func NewIntegrationGRPCServer(service *service.IntegrationService, logger *zap.Logger) *IntegrationGRPCServer {
	return &IntegrationGRPCServer{
		service: service,
		logger:  logger,
	}
}

// Jira RPCs
func (s *IntegrationGRPCServer) SyncTicketToJira(ctx context.Context, req *integrationv1.SyncTicketToJiraRequest) (*integrationv1.SyncTicketToJiraResponse, error) {
	jiraIssue, err := s.service.SyncTicketToJira(ctx, req.TicketId, req.ProjectKey, req.IssueType)
	if err != nil {
		s.logger.Error("Failed to sync ticket to Jira",
			zap.String("ticket_id", req.TicketId),
			zap.Error(err))
		return &integrationv1.SyncTicketToJiraResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	return &integrationv1.SyncTicketToJiraResponse{
		Success:   true,
		Message:   "Ticket synced to Jira successfully",
		JiraIssue: convertToProtoJiraIssue(jiraIssue),
	}, nil
}

func (s *IntegrationGRPCServer) SyncJiraIssue(ctx context.Context, req *integrationv1.SyncJiraIssueRequest) (*integrationv1.SyncJiraIssueResponse, error) {
	ticketID, err := s.service.SyncJiraIssue(ctx, req.JiraKey)
	if err != nil {
		s.logger.Error("Failed to sync Jira issue",
			zap.String("jira_key", req.JiraKey),
			zap.Error(err))
		return &integrationv1.SyncJiraIssueResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	return &integrationv1.SyncJiraIssueResponse{
		Success:  true,
		Message:  "Jira issue synced to ticket successfully",
		TicketId: ticketID,
	}, nil
}

func (s *IntegrationGRPCServer) GetJiraConfig(ctx context.Context, req *integrationv1.GetJiraConfigRequest) (*integrationv1.GetJiraConfigResponse, error) {
	config, err := s.service.GetJiraConfig(ctx)
	if err != nil {
		s.logger.Error("Failed to get Jira config", zap.Error(err))
		return nil, err
	}

	if config == nil {
		return &integrationv1.GetJiraConfigResponse{}, nil
	}

	return &integrationv1.GetJiraConfigResponse{
		Config: convertToProtoJiraConfig(config),
	}, nil
}

func (s *IntegrationGRPCServer) UpdateJiraConfig(ctx context.Context, req *integrationv1.UpdateJiraConfigRequest) (*integrationv1.UpdateJiraConfigResponse, error) {
	config := &models.JiraConfig{
		BaseURL:          req.BaseUrl,
		Username:         req.Username,
		APIToken:         req.ApiToken,
		ProjectKey:       req.ProjectKey,
		DefaultIssueType: req.DefaultIssueType,
		AutoSync:         req.AutoSync,
	}

	err := s.service.UpdateJiraConfig(ctx, config)
	if err != nil {
		s.logger.Error("Failed to update Jira config", zap.Error(err))
		return &integrationv1.UpdateJiraConfigResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	return &integrationv1.UpdateJiraConfigResponse{
		Success: true,
		Message: "Jira configuration updated successfully",
		Config:  convertToProtoJiraConfig(config),
	}, nil
}

// PagerDuty RPCs
func (s *IntegrationGRPCServer) CreatePagerDutyIncident(ctx context.Context, req *integrationv1.CreatePagerDutyIncidentRequest) (*integrationv1.CreatePagerDutyIncidentResponse, error) {
	incident, err := s.service.CreatePagerDutyIncident(ctx, req.Title, req.Description, req.Urgency, req.AlertId)
	if err != nil {
		s.logger.Error("Failed to create PagerDuty incident",
			zap.String("title", req.Title),
			zap.Error(err))
		return &integrationv1.CreatePagerDutyIncidentResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	return &integrationv1.CreatePagerDutyIncidentResponse{
		Success:  true,
		Message:  "PagerDuty incident created successfully",
		Incident: convertToProtoPagerDutyIncident(incident),
	}, nil
}

func (s *IntegrationGRPCServer) GetPagerDutyIncident(ctx context.Context, req *integrationv1.GetPagerDutyIncidentRequest) (*integrationv1.GetPagerDutyIncidentResponse, error) {
	incident, err := s.service.GetPagerDutyIncident(ctx, req.IncidentId)
	if err != nil {
		s.logger.Error("Failed to get PagerDuty incident",
			zap.String("incident_id", req.IncidentId),
			zap.Error(err))
		return nil, err
	}

	return &integrationv1.GetPagerDutyIncidentResponse{
		Incident: convertToProtoPagerDutyIncident(incident),
	}, nil
}

func (s *IntegrationGRPCServer) UpdatePagerDutyIncident(ctx context.Context, req *integrationv1.UpdatePagerDutyIncidentRequest) (*integrationv1.UpdatePagerDutyIncidentResponse, error) {
	err := s.service.UpdatePagerDutyIncident(ctx, req.IncidentId, req.Status, req.ResolutionNote)
	if err != nil {
		s.logger.Error("Failed to update PagerDuty incident",
			zap.String("incident_id", req.IncidentId),
			zap.Error(err))
		return &integrationv1.UpdatePagerDutyIncidentResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	// Get updated incident
	incident, _ := s.service.GetPagerDutyIncident(ctx, req.IncidentId)

	return &integrationv1.UpdatePagerDutyIncidentResponse{
		Success:  true,
		Message:  "PagerDuty incident updated successfully",
		Incident: convertToProtoPagerDutyIncident(incident),
	}, nil
}

func (s *IntegrationGRPCServer) GetPagerDutyConfig(ctx context.Context, req *integrationv1.GetPagerDutyConfigRequest) (*integrationv1.GetPagerDutyConfigResponse, error) {
	config, err := s.service.GetPagerDutyConfig(ctx)
	if err != nil {
		s.logger.Error("Failed to get PagerDuty config", zap.Error(err))
		return nil, err
	}

	if config == nil {
		return &integrationv1.GetPagerDutyConfigResponse{}, nil
	}

	return &integrationv1.GetPagerDutyConfigResponse{
		Config: convertToProtoPagerDutyConfig(config),
	}, nil
}

func (s *IntegrationGRPCServer) UpdatePagerDutyConfig(ctx context.Context, req *integrationv1.UpdatePagerDutyConfigRequest) (*integrationv1.UpdatePagerDutyConfigResponse, error) {
	config := &models.PagerDutyConfig{
		APIKey:             req.ApiKey,
		ServiceID:          req.ServiceId,
		EscalationPolicyID: req.EscalationPolicyId,
		AutoCreateIncident: req.AutoCreateIncident,
	}

	err := s.service.UpdatePagerDutyConfig(ctx, config)
	if err != nil {
		s.logger.Error("Failed to update PagerDuty config", zap.Error(err))
		return &integrationv1.UpdatePagerDutyConfigResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	return &integrationv1.UpdatePagerDutyConfigResponse{
		Success: true,
		Message: "PagerDuty configuration updated successfully",
		Config:  convertToProtoPagerDutyConfig(config),
	}, nil
}

// Generic Integration RPCs
func (s *IntegrationGRPCServer) ListIntegrations(ctx context.Context, req *integrationv1.ListIntegrationsRequest) (*integrationv1.ListIntegrationsResponse, error) {
	integrations := []*integrationv1.Integration{}

	// Check Jira
	jiraConfig, _ := s.service.GetJiraConfig(ctx)
	if jiraConfig != nil {
		integrations = append(integrations, &integrationv1.Integration{
			Id:     "jira",
			Type:   integrationv1.IntegrationType_INTEGRATION_TYPE_JIRA,
			Name:   "Jira",
			Status: integrationv1.IntegrationStatus_INTEGRATION_STATUS_ACTIVE,
		})
	}

	// Check PagerDuty
	pdConfig, _ := s.service.GetPagerDutyConfig(ctx)
	if pdConfig != nil {
		integrations = append(integrations, &integrationv1.Integration{
			Id:     "pagerduty",
			Type:   integrationv1.IntegrationType_INTEGRATION_TYPE_PAGERDUTY,
			Name:   "PagerDuty",
			Status: integrationv1.IntegrationStatus_INTEGRATION_STATUS_ACTIVE,
		})
	}

	return &integrationv1.ListIntegrationsResponse{
		Integrations: integrations,
	}, nil
}

func (s *IntegrationGRPCServer) TestIntegration(ctx context.Context, req *integrationv1.TestIntegrationRequest) (*integrationv1.TestIntegrationResponse, error) {
	switch req.Type {
	case integrationv1.IntegrationType_INTEGRATION_TYPE_JIRA:
		config, err := s.service.GetJiraConfig(ctx)
		if err != nil || config == nil {
			return &integrationv1.TestIntegrationResponse{
				Success: false,
				Message: "Jira not configured",
			}, nil
		}
		// Test is done in UpdateJiraConfig, so if config exists, it's working
		return &integrationv1.TestIntegrationResponse{
			Success: true,
			Message: "Jira connection successful",
		}, nil

	case integrationv1.IntegrationType_INTEGRATION_TYPE_PAGERDUTY:
		config, err := s.service.GetPagerDutyConfig(ctx)
		if err != nil || config == nil {
			return &integrationv1.TestIntegrationResponse{
				Success: false,
				Message: "PagerDuty not configured",
			}, nil
		}
		return &integrationv1.TestIntegrationResponse{
			Success: true,
			Message: "PagerDuty connection successful",
		}, nil

	default:
		return &integrationv1.TestIntegrationResponse{
			Success: false,
			Message: "Unknown integration type",
		}, nil
	}
}

// Helper conversion functions
func convertToProtoJiraConfig(config *models.JiraConfig) *integrationv1.JiraConfig {
	return &integrationv1.JiraConfig{
		Id:               config.ID,
		BaseUrl:          config.BaseURL,
		Username:         config.Username,
		ApiToken:         config.APIToken,
		ProjectKey:       config.ProjectKey,
		DefaultIssueType: config.DefaultIssueType,
		AutoSync:         config.AutoSync,
		CreatedAt:        timestamppb.New(config.CreatedAt),
		UpdatedAt:        timestamppb.New(config.UpdatedAt),
	}
}

func convertToProtoJiraIssue(issue *models.JiraIssue) *integrationv1.JiraIssue {
	return &integrationv1.JiraIssue{
		Key:         issue.Key,
		Id:          issue.ID,
		Summary:     issue.Summary,
		Description: issue.Description,
		IssueType:   issue.IssueType,
		Priority:    issue.Priority,
		Status:      issue.Status,
		Assignee:    issue.Assignee,
		Reporter:    issue.Reporter,
		Created:     timestamppb.New(issue.Created),
		Updated:     timestamppb.New(issue.Updated),
	}
}

func convertToProtoPagerDutyConfig(config *models.PagerDutyConfig) *integrationv1.PagerDutyConfig {
	return &integrationv1.PagerDutyConfig{
		Id:                 config.ID,
		ApiKey:             config.APIKey,
		ServiceId:          config.ServiceID,
		EscalationPolicyId: config.EscalationPolicyID,
		AutoCreateIncident: config.AutoCreateIncident,
		CreatedAt:          timestamppb.New(config.CreatedAt),
		UpdatedAt:          timestamppb.New(config.UpdatedAt),
	}
}

func convertToProtoPagerDutyIncident(incident *models.PagerDutyIncident) *integrationv1.PagerDutyIncident {
	if incident == nil {
		return nil
	}

	var createdAt, updatedAt *timestamppb.Timestamp
	if !incident.CreatedAt.IsZero() {
		createdAt = timestamppb.New(incident.CreatedAt)
	} else {
		createdAt = timestamppb.New(time.Now())
	}
	if !incident.UpdatedAt.IsZero() {
		updatedAt = timestamppb.New(incident.UpdatedAt)
	} else {
		updatedAt = timestamppb.New(time.Now())
	}

	return &integrationv1.PagerDutyIncident{
		Id:                 incident.ID,
		IncidentNumber:     incident.IncidentNumber,
		Title:              incident.Title,
		Description:        incident.Description,
		Status:             incident.Status,
		Urgency:            incident.Urgency,
		ServiceId:          incident.ServiceID,
		EscalationPolicyId: incident.EscalationPolicyID,
		AssigneeIds:        incident.AssigneeIDs,
		CreatedAt:          createdAt,
		UpdatedAt:          updatedAt,
	}
}
